#include <iostream>
#include <string>
#include <thread>
#include <atomic>
#include <mutex>
#include <random>
#include <chrono>
#include <vector>

std::atomic<bool> gab{false};
std::atomic_flag g_flag;

long long GetUTCMS();
int GetRandomNumber();
void ThreadProc(size_t n);
void ThreadProc2(size_t n);

int main(int argc, char const *argv[])
{
    g_flag.clear();
    std::vector<std::thread> v1;
    std::vector<std::thread> v2;
    auto threadNum = std::thread::hardware_concurrency();
    for (size_t i = 0; i < threadNum; i++)
    {
        v1.emplace_back(ThreadProc, i);
        v2.emplace_back(ThreadProc2, i);
    }
    for (auto &t : v2)
    {
        t.join();
    }
    for (auto &t : v1)
    {
        t.join();
    }
    return 0;
}

void ThreadProc(size_t n)
{
    while (!gab.load())
    {
        if (n == GetRandomNumber())
        {
            gab.store(true);
            g_flag.test_and_set();
            g_flag.notify_all();
            printf("set gab true. n=%zd, utc=%lld.\n", n, GetUTCMS());
        }
    }
    printf("ThreadProc1 finished. n=%zd, utc=%lld.\n", n, GetUTCMS());
}

void ThreadProc2(size_t n)
{
    printf("ThreadProc2 wait. n=%zd, gba=%d, utc=%lld.\n", n, gab.load(), GetUTCMS());
    g_flag.wait(false);
    printf("ThreadProc2 finished. n=%zd, gba=%d,utc=%lld.\n", n, gab.load(), GetUTCMS());
}

int GetRandomNumber()
{
    // static std::default_random_engine engine;              // same as "mt19937 eng;"
    static std::random_device sd;                          //生成random_device对象sd做种子
    static std::minstd_rand linearRan(sd());               //使用种子初始化linear_congruential_engine对象，为的是使用它来做我们下面随机分布的种子以输出多个随机分布.注意这里要使用()操作符，因为minst_rand()接受的是一个值（你用srand也是给出这样的一个值）
    static std::uniform_int_distribution<int> dis1(1, 10); //生成01序列
    return dis1(linearRan);
    // 正态分布, 均值10, 标准差3
    // std::normal_distribution<double> distrN(10.0, 0.025);
}

long long GetUTCMS()
{
    return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}